package cn.com.sinux.spring.timing;

import cn.com.sinux.spring.timing.exceptions.NoJobTagException;
import org.apache.commons.lang.StringUtils;
import org.quartz.*;

import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

/**
 * Created by Administrator on 2016/10/7.
 */
public class QuartzTaskScheduler {
    public QuartzTaskScheduler() {
        triggerMap = new HashMap();
        jobMap = new HashMap();
        jobSuf = "_job";
    }

    public String startSimpleJob(JobConf conf, int repeatInternal, Map args)
            throws SchedulerException {
        String jobTag = conf.getJobTag();
        if (StringUtils.isBlank(jobTag))
            throw new NoJobTagException();
        String group = conf.getGroup();
        if (StringUtils.isBlank(group)) {
            group = "DEFAULT";
            conf.group(group);
        }
        String jobId = (new StringBuilder()).append(jobTag).append(jobSuf).append(getIdNum()).toString();
        if (null == args)
            args = new HashMap();
        args.put("jobId", jobId);
        args.put("jobConf", conf);
        JobDataMap dataMap = new JobDataMap();
        dataMap.put("serviceTag", jobTag);
        dataMap.put("args", args);
        Class excuteClass = conf.isConcurrent() ? QuartzJobBean.class : StatefulQuartzJobBean.class;
        JobDetail jobDetail = JobBuilder.newJob(excuteClass).setJobData(dataMap).storeDurably(true).withIdentity(jobId, group).build();
        SimpleScheduleBuilder builder;
        if (repeatInternal == -1)
            builder = SimpleScheduleBuilder.simpleSchedule();
        else
            builder = SimpleScheduleBuilder.simpleSchedule().repeatForever().withIntervalInSeconds(repeatInternal);
        SimpleTrigger simpleTrigger = (SimpleTrigger) TriggerBuilder.newTrigger().withIdentity(jobId, group).withSchedule(builder).forJob(jobId, group).build();
        taskScheduler.scheduleJob(jobDetail, simpleTrigger);
        jobMap.put(jobId, jobDetail);
        triggerMap.put(jobId, simpleTrigger);
        return jobId;
    }

    /**
     * @deprecated Method rescheduleSimpleJob is deprecated
     */

    protected String rescheduleSimpleJob(String jobId, int newInternal)
            throws SchedulerException {
        Map args = (Map) ((JobDetail) jobMap.get(jobId)).getJobDataMap().get("args");
        JobConf conf = (JobConf) args.get("jobConf");
        SimpleTrigger simpleTrigger = (SimpleTrigger) TriggerBuilder.newTrigger().withIdentity(jobId, conf.getGroup()).withSchedule(SimpleScheduleBuilder.simpleSchedule().repeatForever().withIntervalInSeconds(newInternal)).forJob(jobId, conf.getGroup()).build();
        Trigger old = (Trigger) triggerMap.get(jobId);
        taskScheduler.rescheduleJob(old.getKey(), simpleTrigger);
        return jobId;
    }

    protected void startSimpleTriggerForJob(String jobId, int newInternal, Map args)
            throws SchedulerException {
        args = ((Map) (null != args ? args : ((Map) (new HashMap()))));
        JobDetail job = (JobDetail) jobMap.get(jobId);
        Map src = (Map) job.getJobDataMap().get("args");
        JobConf conf = (JobConf) src.get("jobConf");
        String group = conf.getGroup();
        SimpleScheduleBuilder builder;
        if (newInternal == -1)
            builder = SimpleScheduleBuilder.simpleSchedule();
        else
            builder = SimpleScheduleBuilder.simpleSchedule().repeatForever().withIntervalInSeconds(newInternal);
        SimpleTrigger simpleTrigger = (SimpleTrigger) TriggerBuilder.newTrigger().withIdentity(jobId, group).withSchedule(builder).forJob(jobId, group).build();
        src.putAll(args);
        job.getJobDataMap().put("args", src);
        taskScheduler.deleteJob(job.getKey());
        taskScheduler.scheduleJob(job, simpleTrigger);
        triggerMap.put(jobId, simpleTrigger);
    }

    public void refreshSimpleJob(String jobId, int newInternal, Map args)
            throws SchedulerException {
        unscheduleJob(jobId);
        startSimpleTriggerForJob(jobId, newInternal, args);
    }

    public String startCronJob(JobConf conf, String cron, Map args)
            throws SchedulerException {
        String jobTag = conf.getJobTag();
        if (StringUtils.isBlank(jobTag))
            throw new NoJobTagException();
        String group = conf.getGroup();
        if (StringUtils.isBlank(group)) {
            group = "DEFAULT";
            conf.group(group);
        }
        String jobId = (new StringBuilder()).append(jobTag).append(jobSuf).append(getIdNum()).toString();
        if (null == args)
            args = new HashMap();
        args.put("jobId", jobId);
        args.put("jobConf", conf);
        JobDataMap dataMap = new JobDataMap();
        dataMap.put("serviceTag", jobTag);
        dataMap.put("args", args);
        Class excuteClass = conf.isConcurrent() ? QuartzJobBean.class : StatefulQuartzJobBean.class;
        JobDetail jobDetail = JobBuilder.newJob(excuteClass).setJobData(dataMap).storeDurably(true).withIdentity(jobId, group).build();
        CronTrigger cronTrigger = (CronTrigger) TriggerBuilder.newTrigger().withIdentity(jobId, group).withSchedule(CronScheduleBuilder.cronSchedule(cron)).forJob(jobId, group).build();
        taskScheduler.scheduleJob(jobDetail, cronTrigger);
        jobMap.put(jobId, jobDetail);
        triggerMap.put(jobId, cronTrigger);
        return jobId;
    }

    protected void startCronTriggerForJob(String jobId, String newCron, Map args)
            throws SchedulerException {
        args = ((Map) (null != args ? args : ((Map) (new HashMap()))));
        JobDetail job = (JobDetail) jobMap.get(jobId);
        Map src = (Map) job.getJobDataMap().get("args");
        JobConf conf = (JobConf) src.get("jobConf");
        String group = conf.getGroup();
        src.putAll(args);
        job.getJobDataMap().put("args", src);
        CronTrigger cronTrigger = (CronTrigger) TriggerBuilder.newTrigger().withIdentity(jobId, group).withSchedule(CronScheduleBuilder.cronSchedule(newCron)).forJob(jobId, group).build();
        taskScheduler.deleteJob(job.getKey());
        taskScheduler.scheduleJob(job, cronTrigger);
        triggerMap.put(jobId, cronTrigger);
    }

    public void refreshCronJob(String jobId, String newCron, Map args)
            throws SchedulerException {
        unscheduleJob(jobId);
        startCronTriggerForJob(jobId, newCron, args);
    }

    public void terminateJob(String jobId)
            throws SchedulerException {
        Trigger trigger = (Trigger) triggerMap.get(jobId);
        taskScheduler.unscheduleJob(trigger.getKey());
        JobDetail job = (JobDetail) jobMap.get(jobId);
        taskScheduler.deleteJob(job.getKey());
        triggerMap.remove(jobId);
        jobMap.remove(jobId);
    }

    protected void unscheduleJob(String jobId)
            throws SchedulerException {
        Trigger trigger = (Trigger) triggerMap.get(jobId);
        taskScheduler.unscheduleJob(trigger.getKey());
        triggerMap.remove(jobId);
    }

    /**
     * @deprecated Method deleteJob is deprecated
     */

    protected void deleteJob(String jobId) {
        try {
            JobDetail job = (JobDetail) jobMap.get(jobId);
            taskScheduler.deleteJob(job.getKey());
            jobMap.remove(jobId);
        } catch (SchedulerException e) {
            e.printStackTrace();
        }
    }

    private String getIdNum() {
        return (new StringBuilder()).append("_").append(GetGUID()).toString();
    }

    private String GetGUID() {
        UUID uuid = UUID.randomUUID();
        String ruid = "";
        if (uuid.toString().length() <= 32)
            ruid = uuid.toString();
        else
            ruid = uuid.toString().replace("-", "");
        return ruid;
    }

    private Scheduler taskScheduler;
    private Map triggerMap;
    private Map jobMap;
    private String jobSuf;
}
